# gozerbot/ircevent.py
#
#
# http://www.irchelp.org/irchelp/rfc/rfc2812.txt

""" an ircevent is extracted from the IRC string received from the server. """

__status__ = "seen"

## gozerbot imports

from gozerbot.utils.log import rlog
from gozerbot.utils.generic import fix_format, toenc, fromenc, stripident
from gozerbot.eventbase import EventBase, makeargrest
from gozerbot.stats import stats
from gozerbot.config import config

## basic imports

import time
import re
import types
import copy

## defines1

cpy = copy.deepcopy

try:
    dotchars = config['dotchars']
    if not dotchars: dotchars = ' .. '
except KeyError: dotchars = ' .. '

## makeargrest function

def makeargrest(ievent):
    """ 
         create ievent.args and ievent.rest .. this is needed because
         ircevents might be created outside the parse() function.

    """ 
    try: ievent.args = ievent.txt.split()[1:]
    except ValueError: ievent.args = []
    try: cmnd, ievent.rest = ievent.txt.split(' ', 1)
    except ValueError: ievent.rest = ""   
    ievent.command = ievent.txt.split(' ')[0]

## Ircevent class

class Ircevent(EventBase):

    """ represents an IRC event. """

    def __copy__(self):
        return Ircevent(self)

    def __deepcopy__(self, bla):
        return Ircevent(self)
    
    def toirc(self):
        pass

    def parse(self, bot, rawstr):
        """ parse raw string into ircevent. """
        self.bot = bot
        stats.up('events', bot.name)
        bot.nrevents += 1 
        rawstr = rawstr.rstrip()
        splitted = re.split('\s+', rawstr)
        if not rawstr[0] == ':':
            splitted.insert(0, ":none!none@none")
            rawstr = ":none!none@none " + rawstr
        self.prefix = splitted[0][1:]
        nickuser = self.prefix.split('!')
        if len(nickuser) == 2:
            self.nick = nickuser[0]
            stats.up('events', self.nick)
            if self.bot.cfg['stripident'] or config['stripident']: self.userhost = stripident(nickuser[1])
            else: self.userhost = nickuser[1]
        self.cmnd = splitted[1]
        self.cbtype = self.cmnd
        stats.up('events', self.cmnd)
        if pfc.has_key(self.cmnd):
            self.arguments = splitted[2:pfc[self.cmnd]+2]
            txtsplit = re.split('\s+', rawstr, pfc[self.cmnd]+2)
            self.txt = txtsplit[-1]
        else: self.arguments = splitted[2:]
        if self.arguments: self.target = self.arguments[0]
        self.postfix = ' '.join(self.arguments)
        if self.target and self.target.startswith(':'): self.txt = ' '.join(self.arguments)
        if self.txt and self.txt[0] == ":": self.txt = self.txt[1:]
        rlog(0, 'ircevent',"%s %s %s" % (self.cmnd, self.arguments, self.txt))
        if self.cmnd == 'PING': self.speed = 10
        if self.cmnd == 'PRIVMSG':
            self.channel = self.arguments[0]
            if '\001' in self.txt: self.isctcp = True
        elif self.cmnd == 'JOIN' or self.cmnd == 'PART':
            if self.arguments: self.channel = self.arguments[0]
            else: self.channel = self.txt
        elif self.cmnd == 'MODE': self.channel = self.arguments[0]
        elif self.cmnd == 'TOPIC': self.channel = self.arguments[0]
        elif self.cmnd == 'KICK': self.channel = self.arguments[0]
        elif self.cmnd == '353': self.channel = self.arguments[2]
        elif self.cmnd == '324': self.channel = self.arguments[1]
        if self.userhost:
            self.ruserhost = self.userhost
            self.stripped = self.userhost
            self.user = stripident(self.userhost).split('@')[0]
        self.origtxt = self.txt
        self.channel = self.channel.strip()
        stats.up('events', self.channel)
        self.origchannel = self.channel
        rlog(-1, 'ircevent', self)
        try:
            nr = int(self.cmnd)
            if nr > 399: rlog(10, bot.name + '.error', '%s: %s %s' % (self.cmnd, self.arguments, self.txt))
        except ValueError: pass
        return self

    def reply(self, txt, result=None, nick=None, dot=False, nritems=False, nr=False, fromm=None, private=False, how=''):
        """ send reply to the channel the event originated from. """
        if result == []: return
        stats.up('events', 'replies')
        if not how:
            try: how = self.options['--how']        
            except KeyError: how = 'msg'
        restxt = ""
        splitted = []
        if type(result) == types.DictType:
            for i, j in result.iteritems():
                if type(j) == types.ListType:
                    try: z = dotchars.join(j)
                    except TypeError: z = unicode(j)
                else: z = j
                res = "%s: %s" % (i, z)
                splitted.append(res)
                if dot == True: restxt += "%s%s" % (res, dotchars)
                else: restxt += "%s %s" % (dot or ' ', res)
            if restxt:
                if dot == True: restxt = restxt[:-6]
                elif dot: restxt = restxt[:-len(dot)]
        lt = False # set if result is list
        if type(txt) == types.ListType and not result:
            result = txt
            origtxt = u""
            lt = True
        else: origtxt = txt
        if result: lt = True
        if self.queues:
            for i in self.queues:
                if splitted:
                    for item in splitted: i.put_nowait(item)
                elif lt:
                    for j in result: i.put_nowait(j)
                elif restxt: i.put_nowait(restxt)
                else: i.put_nowait(txt)
            if self.onlyqueues: return
        if not self.bot: rlog(10, 'event', 'no bot defined in event') ; return
        pretxt = origtxt
        if lt and not restxt:
            res = []
            for i in result:
                if type(i) == types.ListType or type(i) == types.TupleType:
                    try: res.append(dotchars.join(i))
                    except TypeError: res.extend(i)
                else: res.append(i)
            result = res
            if nritems:
                if len(result) > 1: pretxt += "(%s items) .. " % len(result)
            txtlist = result
            if not nr is False:
                try: start = int(nr)
                except ValueError: start = 0
                txtlist2 = []
                teller = start
                for i in txtlist:
                    txtlist2.append(u"%s) %s" % (teller, i))
                    teller += 1
                txtlist = txtlist2
            txtl = []
            for item in txtlist: txtl.append(toenc(item))
            txtlist = txtl
            if dot == True: restxt = dotchars.join(txtlist)
            elif dot: restxt = dot.join(txtlist)
            else: restxt = ' '.join(txtlist)
        if pretxt:
            try: restxt = pretxt + restxt
            except TypeError: rlog(10, 'eventbase', "can't add %s and %s" % (str(pretxt), str(restxt)))
        if self.filtered(restxt): return
        if self.cmnd == 'DCC' and self.sock:
            self.bot.say(self.sock, restxt, speed=self.speed, how=how)
            return
        if nick:
            self.bot.say(nick, restxt, fromm=nick, speed=self.speed, how=how)
            return
        if self.msg or private:
            self.bot.say(self.nick, restxt, fromm=self.nick, speed=self.speed, how=how)
            return
        silent = False
        channel = self.printto or self.channel
        try: silent = self.bot.channels[channel]['silent']
        except (KeyError, TypeError): pass
        fromm = fromm or self.nick
        if silent:
            notice = False
            try: notice = self.bot.channels[channel]['notice']
            except (KeyError, TypeError): pass
            if notice: self.bot.say(self.nick, restxt, how='notice', fromm=fromm, speed=self.speed)
            else: self.bot.say(self.nick, restxt, fromm=fromm, speed=self.speed, how=how)
            return
        if self.printto: self.bot.say(self.printto, restxt, fromm=fromm, speed=self.speed, how=how) ; return
        else: self.bot.say(self.channel, restxt, fromm=fromm, speed=self.speed, how=how)

## defines2

# postfix count aka how many arguments

pfc = {}
pfc['NICK'] = 0
pfc['QUIT'] = 0
pfc['SQUIT'] = 1
pfc['JOIN'] = 0
pfc['PART'] = 1
pfc['TOPIC'] = 1
pfc['KICK'] = 2
pfc['PRIVMSG'] = 1
pfc['NOTICE'] = 1
pfc['SQUERY'] = 1
pfc['PING'] = 0
pfc['ERROR'] = 0
pfc['AWAY'] = 0
pfc['WALLOPS'] = 0
pfc['INVITE'] = 1
pfc['001'] = 1
pfc['002'] = 1
pfc['003'] = 1
pfc['004'] = 4
pfc['005'] = 15
pfc['302'] = 1
pfc['303'] = 1
pfc['301'] = 2
pfc['305'] = 1
pfc['306'] = 1
pfc['311'] = 5
pfc['312'] = 3
pfc['313'] = 2
pfc['317'] = 3
pfc['318'] = 2
pfc['319'] = 2
pfc['314'] = 5
pfc['369'] = 2
pfc['322'] = 3
pfc['323'] = 1
pfc['325'] = 3
pfc['324'] = 4
pfc['331'] = 2
pfc['332'] = 2
pfc['341'] = 3
pfc['342'] = 2
pfc['346'] = 3
pfc['347'] = 2
pfc['348'] = 3
pfc['349'] = 2
pfc['351'] = 3
pfc['352'] = 7
pfc['315'] = 2
pfc['353'] = 3
pfc['366'] = 2
pfc['364'] = 3
pfc['365'] = 2
pfc['367'] = 2
pfc['368'] = 2
pfc['371'] = 1
pfc['374'] = 1
pfc['375'] = 1
pfc['372'] = 1
pfc['376'] = 1
pfc['381'] = 1
pfc['382'] = 2
pfc['383'] = 5
pfc['391'] = 2
pfc['392'] = 1
pfc['393'] = 1
pfc['394'] = 1
pfc['395'] = 1
pfc['262'] = 3
pfc['242'] = 1
pfc['235'] = 3
pfc['250'] = 1
pfc['251'] = 1
pfc['252'] = 2
pfc['253'] = 2
pfc['254'] = 2
pfc['255'] = 1
pfc['256'] = 2
pfc['257'] = 1
pfc['258'] = 1
pfc['259'] = 1
pfc['263'] = 2
pfc['265'] = 1
pfc['266'] = 1
pfc['401'] = 2
pfc['402'] = 2
pfc['403'] = 2
pfc['404'] = 2
pfc['405'] = 2
pfc['406'] = 2
pfc['407'] = 2
pfc['408'] = 2
pfc['409'] = 1
pfc['411'] = 1
pfc['412'] = 1
pfc['413'] = 2
pfc['414'] = 2
pfc['415'] = 2
pfc['421'] = 2
pfc['422'] = 1
pfc['423'] = 2
pfc['424'] = 1
pfc['431'] = 1
pfc['432'] = 2
pfc['433'] = 2
pfc['436'] = 2
pfc['437'] = 2
pfc['441'] = 3
pfc['442'] = 2
pfc['443'] = 3
pfc['444'] = 2
pfc['445'] = 1
pfc['446'] = 1
pfc['451'] = 1
pfc['461'] = 2
pfc['462'] = 1
pfc['463'] = 1
pfc['464'] = 1
pfc['465'] = 1
pfc['467'] = 2
pfc['471'] = 2
pfc['472'] = 2
pfc['473'] = 2
pfc['474'] = 2
pfc['475'] = 2
pfc['476'] = 2
pfc['477'] = 2
pfc['478'] = 3
pfc['481'] = 1
pfc['482'] = 2
pfc['483'] = 1
pfc['484'] = 1
pfc['485'] = 1
pfc['491'] = 1
pfc['501'] = 1
pfc['502'] = 1
pfc['700'] = 2
                
# default event used to initialise events
defaultevent = EventBase()
